﻿using System;
using System.Collections.Generic;

namespace FloppyList
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("FloppyList");
            Console.WriteLine("这个工具用来分析Fat12分区表结构，他遍历根目录所有的文件");
            Console.WriteLine("例 flist d:\\disk.img");
            var file = args[0];

            DumpFatTable(file);
        }
        static void DumpFatTable(string filename)
        {
            var ADDR_FATTABLE = 0x0200 * 1; //1扇区FAT表
            var ADDR_LIST = 0x200 * 19;
            var ADDR_DATA = 0x3E00; ;//扇区号31开始
            //0~`17 在一个磁头一个柱面
            //1~10一次即可取出
            byte[] fattable = new byte[9 * 512];
            byte[] filetable = new byte[14 * 512];

            using (var fs = System.IO.File.OpenRead(filename))
            {
                fs.Seek(ADDR_FATTABLE, System.IO.SeekOrigin.Begin);
                fs.Read(fattable, 0, fattable.Length);

                fs.Seek(ADDR_LIST, System.IO.SeekOrigin.Begin);
                fs.Read(filetable, 0, filetable.Length);
            }
            System.Collections.Generic.Dictionary<string, int> fileaddrs = new System.Collections.Generic.Dictionary<string, int>();
            for (var i = 0; i < filetable.Length; i += 32)
            {
                if (filetable[i] == 0) break;

                var byteatt = filetable[i + 0x0b];
                var fatindex = BitConverter.ToUInt16(filetable, i + 0x1A);
                if (byteatt == 0x0f)//longnamemode
                {
                    var nameid = filetable[i] & 0x1F;
                    var end = (filetable[i] & 0xD0) > 0;
                    ;// 0x01 10
                    //0x0e 12
                    var crc = filetable[i + 0x0d];

                    var name1 = System.Text.Encoding.Unicode.GetString(filetable, i + 0x01, 10);
                    var name2 = filetable[i + 0x0e] > 0 ? System.Text.Encoding.Unicode.GetString(filetable, i + 0x0e, 12) : "";
                    var name3 = filetable[i + 0x1c] > 0 ? System.Text.Encoding.Unicode.GetString(filetable, i + 0x1c, 4) : "";

                    Console.WriteLine("name:" + name1 + name2 + name3 + " nameid=" + nameid + " end=" + end + " crc" + crc + " fatindex=" + fatindex);
                }
                else
                {
                    //0x00filename
                    var name = System.Text.Encoding.ASCII.GetString(filetable, i, 8);
                    var extname = System.Text.Encoding.ASCII.GetString(filetable, i + 8, 3);

                    fileaddrs[name + "." + extname] = fatindex;

                    //0x0b att
                    //var byteatt = filetable[i + 0x0b];
                    //0x0c ~0x15 nouse

                    var date = BitConverter.ToUInt16(filetable, i + 0x16);
                    var time = BitConverter.ToUInt16(filetable, i + 0x18);
                    //var fatindex = BitConverter.ToUInt16(filetable, i + 0x1A);
                    var filelen = BitConverter.ToUInt32(filetable, i + 0x1C);
                    Console.WriteLine("name:" + name + "." + extname + " len=" + filelen + "   fatindex=" + fatindex);
                }
            }

            foreach (var file in fileaddrs)
            {
                List<byte[]> fileblocks = new List<byte[]>();
                Console.WriteLine("Dump file fat:" + file.Key);
                UInt16 nextaddr = (UInt16)file.Value;

                var posindex = nextaddr / 2 * 3;
                var outstr = "";
                while (nextaddr < 0x8ff)
                {
                    outstr += nextaddr.ToString("X02") + " ";

                    //读取文件
                    var fileaddr = ADDR_DATA + nextaddr * 0x200;
                    var bytes = new byte[0x200];
                    using (var fs = System.IO.File.OpenRead(filename))
                    {
                        fs.Seek(fileaddr, System.IO.SeekOrigin.Begin);
                        fs.Read(bytes, 0, bytes.Length);
                    }
                    fileblocks.Add(bytes);

                    //下一块
                    var ishigh = nextaddr % 2;
                    if (ishigh > 0)
                    {
                        nextaddr = (UInt16)((fattable[posindex + 1] & 0xF0) / 0x10 + fattable[posindex + 2] * 0x10);
                    }
                    else
                    {
                        nextaddr = (UInt16)(fattable[posindex] + (fattable[posindex + 1] & 0x0f) * 0x100);
                    }
                    posindex = nextaddr / 2 * 3;

                }
                Console.WriteLine(outstr);

                foreach(var b in fileblocks)
                {
                    var bhex = "";
                    foreach(var bb in b)
                    {
                        bhex += bb.ToString("X02");
                    }
                    Console.WriteLine("Dump block:");
                    Console.WriteLine(bhex);
                    Console.WriteLine(System.Text.Encoding.UTF8.GetString(b));
                }

            }
        }
    }
}
